//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Text;
using System.Windows.Threading;

namespace OpenLS.Chart.UI
{
    class ProgressiveCollection<T> : ComplexCollection<T>
    {

        public ProgressiveCollection(IList<T> collection, int count)
            : base(collection)
        {
            this._count = Math.Min(collection.Count, count);
            if (_count < collection.Count)
            {
                timer = new DispatcherTimer(DispatcherPriority.SystemIdle);
                timer.Tick += new EventHandler(timer_Tick);
                timer.Interval = new TimeSpan(0, 0, 0, 0);
                timer.Start();
            }

        }


        private WeakListener<INotifyCollectionChanged, NotifyCollectionChangedEventArgs> collectionWeakListener;
        //        private WeakListener<INotifyCollectionChanged, EventArgs> timerWeakListener;

        public void timer_Tick(object sender, EventArgs e)
        {
            _count++;
            if (_count >= _inner.Count)
            {
                timer.Tick -= this.timer_Tick;
                timer.Stop();
            }
            //  InvokeCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            InvokeCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,
                _inner[_count - 1], _count - 1));
            InvokePropertyChanged(new PropertyChangedEventArgs("Count"));
        }

        private readonly DispatcherTimer timer;

        private int _count = 500;


        public override IEnumerator<T> GetEnumerator()
        {
            return Enumerable.Take(_inner, _count).GetEnumerator();
        }


        public override int Count
        {
            get { return _count; }
        }


        public override T this[int index]
        {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }
    }
    class ModuloCollection<T> : ComplexCollection<T>
    {
        private readonly int _modulo;
#if DEBUG
        [ContractInvariantMethod]
        private void ObjectInvariant()
        {
            Contract.Invariant(_modulo > 0);
        }
#endif

        private WeakListener<INotifyCollectionChanged, NotifyCollectionChangedEventArgs> collectionWeakListener;

        public ModuloCollection(IList<T> inner, int modulo)
            : base(inner)
        {
            this._modulo = modulo;
        }

        public override IEnumerator<T> GetEnumerator()
        {
            int m = 0;
            foreach (var item in _inner)
            {
                if (m == 0)
                    yield return item;
                m++;
                m = m % _modulo;
            }
        }


        public override int Count
        {
            get { return _inner.Count / _modulo; }
        }

        public override T this[int index]
        {
            get { return _inner[index / _modulo]; }
            set { _inner[index / _modulo] = value; }
        }
    }

    class WeakListener<TInterface, TEventArgs> where TInterface : class
    {
        internal delegate void Del(object sender, NotifyCollectionChangedEventArgs e);
        private readonly Action<Del> _unregisterAction;
        private readonly WeakReference _weakTarget;
        private readonly MethodInfo _methodInfo;

        public WeakListener(Action<Del> action, TInterface target, MethodInfo methodInfo)
        {
            Contract.Requires(target != null);
            Contract.Requires(methodInfo != null);
            _unregisterAction = action;
            _weakTarget = new WeakReference(target, false);
            _methodInfo = methodInfo;
        }

        public void DoIt(object sender, TEventArgs e)
        {
            TInterface actualTarget = (TInterface)_weakTarget.Target;
            if (actualTarget == null)
            {
                unregister();
            }
            else
            {
                _methodInfo.Invoke(actualTarget, BindingFlags.Instance, null, new object[] { e }, null);

            }
        }

        private void unregister()
        {
            _unregisterAction(null);
        }

    }

}
